#include "sk_game_project.h"
#include "sk_swap.h"
#include "sk_game_shape.h"

#include <QObject>
#include <QFileInfo>
#include <QDebug>
#include <QDir>
#include <QDomElement>
#include <QDomDocument>

namespace sk
{

GameProject::GameProject()
{
    _isEmpty = true;
}

bool GameProject::isEmpty() const
{
    return _isEmpty;
}

bool GameProject::isDirty() const
{
    return _isDirty;
}

void GameProject::setDirty(bool d)
{
    _isDirty = d;
}

void GameProject::removeLevel(int ind)
{
    Q_ASSERT(ind >= 0 && ind < levels.size());
    levels.erase(levels.begin() + ind);
    _isDirty = true;
}

void GameProject::cloneLevel(int ind)
{
    Q_ASSERT(ind >= 0 && ind < levels.size());
    levels.push_back(levels[ind]);
    for (int i = 0; i < levels.back().shapes.size(); ++i)
    {
        levels.back().shapes[i] = GameShapeRef(levels.back().shapes[i]->clone());
    }
    for (int i = 0; i < levels.back().dropShapes.size(); ++i)
    {
        levels.back().dropShapes[i] = GameShapeRef(levels.back().dropShapes[i]->clone());
    }

}

void GameProject::swapLevels(int i, int j)
{
    if (i == j)
    {
        return;
    }
    Q_ASSERT(i >= 0 && i < levels.size());
    Q_ASSERT(j >= 0 && j < levels.size());
    sk::swap(levels[i], levels[j]);
    _isDirty = true;
}

void GameProject::close(bool save)
{
    if (save)
    {
        saveToDisk();
    }
    _isEmpty = true;
    _isDirty = false;
    _name.clear();
    _projectDir.clear();
    levels.clear();
}

bool GameProject::open(QString path)
{
    errorString.clear();
    QDomDocument doc;
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly))
    {
        errorString = "Can not open file for reading :" + path;
        return false;
    }
    QString errorMsg;
    int errorLine;
    int errorColumn;
    if (!doc.setContent(&file, &errorMsg, &errorLine, &errorColumn))
    {
        errorString = errorMsg + ("\nLine: " + QString::number(errorLine) + " column: " + QString::number(errorColumn));
        file.close();
        return false;
    }
    file.close();
    close(false);
    create(path);

    bool isOk = false;
    for (int i = 0; i < doc.childNodes().count(); ++i)
    {
        QDomElement e = doc.childNodes().at(i).toElement();
        if (e.tagName() == "project")
        {
            isOk = deserialize(&e);
        }
    }
    if (!isOk)
    {
        errorString = ".gameproj is invalid somewhere";
        close(false);
        return false;
    }
    return true;
}

bool GameProject::deserialize(QDomElement * e)
{    
    for (int i = 0; i < e->childNodes().count(); ++i)
    {
        QDomElement ee = e->childNodes().at(i).toElement();
        if (ee.tagName() == "level")
        {
            levels.push_back(GameLevel());
            if (!levels.back().deserialize(&ee))
            {
                return false;
            }
        }
    }
    return true;
}

void GameProject::serialize(QDomDocument * doc, QDomElement * e)
{
    e->setAttribute("name", name());
    for (int i = 0; i < levels.size(); ++i)
    {
        QDomElement ee = doc->createElement("level");
        levels[i].serialize(doc, &ee);
        e->appendChild(ee);
    }
}

QString GameProject::path() const
{
    QDir d(_projectDir);
    return d.absoluteFilePath(name() + ".gameproj");
}

bool GameProject::saveToDisk()
{
    if (isEmpty())
    {
        return true;
    }
    QDomDocument doc;


    QFile file(path());
    if (!file.open(QIODevice::WriteOnly))
    {
        return false;
    }
    QDomElement e = doc.createElement("project");
    doc.appendChild(e);
    serialize(&doc, &e);

    file.write(doc.toByteArray());
    file.close();
    _isDirty = false;
    return true;
}

bool GameProject::create(QString path)
{
    QFileInfo fi(path);
    _name = fi.baseName();
    _projectDir = fi.dir().absolutePath();
    _isEmpty = false;
    _isDirty = false;
    return true;
}


QString GameProject::projectDir() const
{
    if (isEmpty())
    {
        return QObject::tr("Invalid Directory");
    }
    return _projectDir;
}

QString GameProject::name() const
{
    if (isEmpty())
    {
        return QObject::tr("Invalid Project");
    }
    return _name;
}

void GameProject::createLevel(QString name)
{
    levels.push_back(sk::GameLevel());
    levels.back().setName(name);
    _isDirty = true;
}



} // namespace sk

